#include <string.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <ctype.h>

#include <errno.h>

#include <sys/types.h>
#include <sys/time.h>

#include <utility.h>

#include <log.h>

Uint64 get_ticks() {
	static struct timeval startup;
	static bool once = true;
	struct timeval now;

	if (once) {
		once = false;
		gettimeofday(&startup, NULL);
	}
	gettimeofday(&now, NULL);
    Uint64 r = ((now.tv_sec - startup.tv_sec) * 1000) +
        ((now.tv_usec - startup.tv_usec) / 1000);
    return r;
}

/* 创建目录，就好像 mkdir -p 一样，解释 / 分隔符
 * 如果不存在，就创建
 */
bool create_dir(const char *dir)
{
    std::string  path;
    const char  *cur = dir;
    const char  *p;

    errno = 0;

    while (*cur) {
        p = strchr(cur, '/');
        if (p)
            cur = p + 1;
        else {
            p = cur + strlen(cur);
            cur = p;
        }

        path.assign(dir, p - dir);

        if (path.size() > 0) {
            if (!is_dir(path.c_str())) {
                if (mkdir(path.c_str(), 0777) < 0 && errno != EEXIST)
                    return false;
            }
        }
    }

    return true;
}

/* 判断是否普通文件
 */
bool is_reg_file(const char* path)
{
	struct stat sb;

	if(stat(path, &sb) < 0)
		return false;

	return S_ISREG(sb.st_mode);
}

/* 判断是否为目录
 */
bool is_dir(const char* path)
{
	struct stat sb;

	if(stat(path, &sb) < 0)
		return false;

	return S_ISDIR(sb.st_mode);
}

/* sleep 微秒
 */
void sleep_us(int us) {
    struct timeval t;

    t.tv_sec  = us / 1000000;
    t.tv_usec = us % 1000000;
    select(0, NULL, NULL, NULL, &t);
}

void get_date(date_t *d)
{
    time_t     t;
    struct tm  p;

    t = time(NULL);
    (void)localtime_r(&t, &p);

    d->year   = p.tm_year + 1900;
    d->month  = p.tm_mon  + 1;
    d->day    = p.tm_mday;
    d->hour   = p.tm_hour;
    d->minute = p.tm_min;
    d->second = p.tm_sec;
}

void get_date_prev_ndays(date_t *d, int n)
{
    time_t     t;
    struct tm  p;

    t = time(NULL);

    t -= n * 60 * 60 * 24;

    (void)localtime_r(&t, &p);

    d->year   = p.tm_year + 1900;
    d->month  = p.tm_mon  + 1;
    d->day    = p.tm_mday;
    d->hour   = p.tm_hour;
    d->minute = p.tm_min;
    d->second = p.tm_sec;
}

void get_curr_time_fmt(std::string& result)
{
    char       buf[128];
    time_t     now;
    struct tm  p;

    now = time(NULL);
    (void)localtime_r(&now, &p);
    sprintf(buf,
            "%04d-%02d-%02d %02d:%02d:%02d",
            1900 + p.tm_year,
            p.tm_mon + 1,
            p.tm_mday,
            p.tm_hour,
            p.tm_min,
            p.tm_sec);

    result = buf;
}

void get_curr_time(std::string& result)
{
    char       buf[128];
    time_t     now;
    struct tm  p;

    now = time(NULL);
    (void)localtime_r(&now, &p);
    sprintf(buf,
            "%04d%02d%02d%02d%02d%02d",
            1900 + p.tm_year,
            p.tm_mon + 1,
            p.tm_mday,
            p.tm_hour,
            p.tm_min,
            p.tm_sec);

    result = buf;
}

void get_curr_time_spec(std::string&  result,
                        const char   *fmt)
{
    char      buf[64];
    time_t    now;
    struct tm p;

    now = time(NULL);
    (void)localtime_r(&now, &p);

    result.clear();

    while (*fmt) {
        switch (*fmt) {
        case 'Y':
            sprintf(buf, "%04d", 1900 + p.tm_year);
            result += buf;
            break;

        case 'M':
            sprintf(buf, "%02d", 1 + p.tm_mon);
            result += buf;
            break;

        case 'D':
            sprintf(buf, "%02d", p.tm_mday);
            result += buf;
            break;

        case 'h':
            sprintf(buf, "%02d", p.tm_hour);
            result += buf;
            break;

        case 'm':
            sprintf(buf, "%02d", p.tm_min);
            result += buf;
            break;

        case 's':
            sprintf(buf, "%02d", p.tm_sec);
            result += buf;
            break;
        }
        ++fmt;
    }
}

bool all_dig_p(const char *s)
{
    while (*s) {
        if (*s >= '0' && *s <= '9')
            ++s;
        else
            return false;
    }
    return true;
}

int str2int(const char *s, int *res, int len)
{
    int i;

    if (len <= 0)
        len = strlen(s);

    int tmp = 0;

    for (i = 0; i < len; i++) {
        if (s[i] >= '0' && s[i] <= '9') {
            tmp *= 10;
            tmp += s[i] - '0';
        }
        else
            break;
    }

    *res = tmp;

    return i;
}

int parse_time_op(const char *s, date_t& d)
{
    memset(&d, 0, sizeof(date_t));

    // opyyyymmdd
    if (strlen(s) != 10)
        return DATE_OP_UNKNOW;

    std::string ops;
    ops.push_back((*s >= 'A' && *s <= 'Z') ? (*s - 'A' + 'a') : *s);
    ++s;
    ops.push_back((*s >= 'A' && *s <= 'Z') ? (*s - 'A' + 'a') : *s);
    ++s;

    int op;
    if (ops == "lt")
        op = DATE_OP_LT;
    else if (ops == "gt")
        op = DATE_OP_GT;
    else if (ops == "le")
        op = DATE_OP_LE;
    else if (ops == "ge")
        op = DATE_OP_GE;
    else if (ops == "eq")
        op = DATE_OP_EQ;
    else
        return DATE_OP_UNKNOW;

    if (all_dig_p(s) == false)
        return DATE_OP_UNKNOW;

    int year;
    int month;
    int day;

    str2int(s + 0, &year,  4);
    str2int(s + 4, &month, 2);
    str2int(s + 6, &day,   2);

    d.year  = year;
    d.month = month;
    d.day   = day;

    return op;
}

void *util_mem_dup(const void *ptr, int len)
{
    if (len <= 0)
        return NULL;

    void *m = (void *) malloc (len);
    memcpy(m, ptr, len);
    return m;
}
